home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus Special 17
/
AMIGAplus Sonderheft 17 (1999)(ICP)(DE)[!].iso
/
dsound
/
source.lha
/
Play.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-07-18
|
19KB
|
713 lines
/*************************************************************************/
/* Play.c */
/*Contains code used to play samples (mono out of one or both speakers, */
/*and stereo). */
/*************************************************************************/
#include <exec/types.h>
#include <exec/exec.h>
#include <devices/audio.h>
#include <dos/dos.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <graphics/gfxbase.h>
#include <stdlib.h>
#include "dsound.h"
#include <proto/intuition.h>
#include <proto/exec.h>
#include <proto/dos.h>
UBYTE rightAMap[]={4,2,1,8};
UBYTE leftAMap[]={1,8,2,4};
UBYTE eitherAMap[]={1,2,4,8};
UBYTE bothAMap[]={8,3,5,10};
extern UBYTE volume;
extern UWORD speed;
extern ULONG bufSize;
extern BOOL readAll;
extern BOOL loop;
extern struct Window *window;
/*Play a sample out of one speaker (left, right, or either)*/
void playMonoSample(BPTR file,channel audioChannel,struct Voice8Header *vhdr,
ULONG len)
{
struct IOAudio *iob1,*iob2;
ULONG toRead;
ULONG sampleSize=len;
BOOL done=FALSE;
UBYTE *allocationMap;
/*Load the entire sample into memory, if the user so specified*/
if(readAll)
{
storeLeft(file,len,bufSize);
file=0L;
}
/*Decide which audio channel will be allocated*/
switch(audioChannel)
{
case MONO_LEFT:
allocationMap=leftAMap;
break;
case MONO_RIGHT:
allocationMap=rightAMap;
break;
case UNSPECIFIED:
allocationMap=eitherAMap;
break;
}
/*Get the first audio channel*/
iob1=GetAudioChannel(bufSize,allocationMap);
if(iob1==NULL)
{
WriteMsg("Couldn't create the first buffer\n");
cleanup(150);
}
/* If the user didn't specify a volume, get it from the VHDR */
if(volume==0)
volume=(vhdr->volume>>10);
/* If the VHDR gave a volume of zero, use maximum volume*/
if(volume==0)
volume=64;
/* Get the samples/sec rate (either the rate given by the user, or the*/
/* rate found in the VHDR) */
if(speed==0)
speed=1000000000/(vhdr->samplesPerSec*279);
else
speed=1000000000/(speed*279);
InitAudioChannel(iob1,volume,speed);
/*Get the 2nd audio channel*/
iob2=DuplicateAudioChannel(iob1);
if(iob2==NULL)
{
FreeAudioChannel(iob1);
WriteMsg("Couldn't create the second buffer\n");
cleanup(175);
}
/* Load the first buffer*/
toRead=MIN(len,bufSize);
LoadAudioBuffer(file,iob1,toRead);
len-=toRead;
if(len==0 && loop)
{
len=sampleSize;
Seek(file,-sampleSize,OFFSET_CURRENT);
}
/*Store the number of samples to be played*/
iob1->ioa_Length=toRead;
/* Make sure there's enough data so that we have something to put in */
/* the second buffer */
if(len!=0)
{
toRead=MIN(len,bufSize);
LoadAudioBuffer(file,iob2,toRead);
len-=toRead;
if(len==0 && loop)
{
len=sampleSize;
Seek(file,-sampleSize,OFFSET_CURRENT);
}
iob2->ioa_Length=toRead;
}
else
/* It appears that the entire sound sample is small enough to */
/* fit into the first buffer, so don't play the second */
iob2->ioa_Length=0;
/*And queue up the play requests*/
BeginIO((struct IORequest *)iob1);
if(iob2->ioa_Length!=0)
BeginIO((struct IORequest *)iob2);
/* If the sound sample was small enough to fit into the two buffers, */
/* play them then finish up */
if(len==0)
{
Wait((1<<iob1->ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) +
(1<<window->UserPort->mp_SigBit));
/* vvvv Bug fix */
if(iob2->ioa_Length!=0 && GetMsg(window->UserPort)==NULL)
Wait((1<<iob2->ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) |
(1<<window->UserPort->mp_SigBit));
done=TRUE;
}
/*Otherwise, play those samples then read more from disk*/
/*Loop while there's stuff to read*/
while(!done)
{
/*Fill the first buffer*/
Wait((1<<iob1->ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) |
(1<<window->UserPort->mp_SigBit));
toRead=MIN(len,bufSize);
if(GetMsg(window->UserPort)!=NULL)
{
done=TRUE;
break;
}
else
if(toRead==0)
{
/*If there's no stuff left to read, wait 'till the second buffer*/
/*finishes, then quit*/
Wait((1<<iob2->ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) |
(1<<window->UserPort->mp_SigBit));
done=TRUE;
break;
}
LoadAudioBuffer(file,iob1,toRead);
len-=toRead;
if(len==0 && loop)
{
len=sampleSize;
Seek(file,-sampleSize,OFFSET_CURRENT);
}
iob1->ioa_Length=toRead;
/*Play the first buffer*/
BeginIO((struct IORequest *)iob1);
/*Wait for the second buffer to finish*/
Wait((1<<iob2->ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) |
(1<<window->UserPort->mp_SigBit));
toRead=MIN(len,bufSize);
if(GetMsg(window->UserPort)!=NULL)
{
done=TRUE;
break;
}
else
if(toRead==0)
{
/*If there's no stuff left to read, wait 'till the first buffer*/
/*finishes, then quit*/
Wait((1<<iob1->ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) |
(1<<window->UserPort->mp_SigBit));
done=TRUE;
break;
}
/*Reload it*/
LoadAudioBuffer(file,iob2,toRead);
len-=toRead;
if(len==0 && loop)
{
len=sampleSize;
Seek(file,-sampleSize,OFFSET_CURRENT);
}
iob2->ioa_Length=toRead;
/*Play it*/
BeginIO((struct IORequest *)iob2);
}
/*Restore the buffer lengths, so that FreeAudio() channel, etc., knows*/
/*how much memory to free*/
iob1->ioa_Length=iob2->ioa_Length=bufSize;
FreeAudioChannel(iob1);
DeleteDuplication(iob2);
return;
}
/*Play a stereo sample out of both speakers*/
/*If the user specifies that just one of the two stereo channels will*/
/*be played, DSound.c calls playMonoSample*/
void playStereoSample(BPTR leftFile,channel audioChannel,
struct Voice8Header *vhdr, ULONG length, char *filename)
{
struct IOAudio *iob1_right,*iob2_right,*iob1_left,*iob2_left;
ULONG toRead;
ULONG sampleSize=length;
BOOL done=FALSE;
BPTR rightFile;
/*Open the file again*/
rightFile=dupFileHandle(leftFile,filename);
/*And position ourselves at the start of the right channel's data*/
Seek(rightFile,length,OFFSET_CURRENT);
/*Read the entire sample into memory, if specified*/
if(readAll)
{
storeLeft(leftFile,length,bufSize);
storeRight(rightFile,length,bufSize);
Close(rightFile);
leftFile=0L;
rightFile=4L;
}
/*Get the first audio channel*/
iob1_left=GetAudioChannel(bufSize,leftAMap);
if(iob1_left==NULL)
{
WriteMsg("Couldn't create the first stereo buffer\n");
cleanup(150);
}
iob1_right=GetAudioChannel(bufSize,rightAMap);
if(iob1_right==NULL)
{
WriteMsg("Couldn't create the second stereo buffer\n");
cleanup(150);
}
/* If the user didn't specify a volume, get it from the VHDR */
if(volume==0)
volume=(vhdr->volume>>10);
/* If the VHDR gave a volume of zero, use maximum volume*/
if(volume==0)
volume=64;
/* Get the samples/sec rate (either the rate given by the user, or the*/
/* rate found in the VHDR) */
if(speed==0)
speed=1000000000/(vhdr->samplesPerSec*279);
else
speed=1000000000/(speed*279);
InitAudioChannel(iob1_left,volume,speed);
InitAudioChannel(iob1_right,volume,speed);
/*Get the 2nd audio channel*/
iob2_left=DuplicateAudioChannel(iob1_left);
if(iob2_left==NULL)
{
FreeAudioChannel(iob1_left);
FreeAudioChannel(iob1_right);
WriteMsg("Couldn't create the second buffer");
cleanup(175);
}
iob2_right=DuplicateAudioChannel(iob1_right);
if(iob2_right==NULL)
{
FreeAudioChannel(iob1_left);
DeleteDuplication(iob2_left);
FreeAudioChannel(iob1_right);
WriteMsg("Couldn't create the second buffer");
cleanup(175);
}
/* Load the first buffer*/
toRead=MIN(length,bufSize);
LoadAudioBuffer(leftFile,iob1_left,toRead);
LoadAudioBuffer(rightFile,iob1_right,toRead);
iob1_left->ioa_Length=iob1_right->ioa_Length=toRead;
iob1_right->ioa_Length=iob1_left->ioa_Length=toRead;
length-=toRead;
if(length==0 && loop)
{
length=sampleSize;
Seek(leftFile,-sampleSize,OFFSET_CURRENT);
Seek(rightFile,-sampleSize,OFFSET_CURRENT);
}
/* Make sure there's enough data so that we have something to put in */
/* the second buffer */
if(length!=0)
{
toRead=MIN(length,bufSize);
LoadAudioBuffer(leftFile,iob2_left,toRead);
LoadAudioBuffer(rightFile,iob2_right,toRead);
length-=toRead;
if(length==0 && loop)
{
length=sampleSize;
Seek(leftFile,-sampleSize,OFFSET_CURRENT);
Seek(rightFile,-sampleSize,OFFSET_CURRENT);
}
iob2_right->ioa_Length=iob2_left->ioa_Length=toRead;
}
else
/* It appears that the entire sound sample is small enough to */
/* fit into the first buffer, so don't play the second */
iob2_left->ioa_Length=iob2_right->ioa_Length=0;
/*And queue up the play requests*/
BeginIO((struct IORequest *)iob1_left);
BeginIO((struct IORequest *)iob1_right);
if(iob2_left->ioa_Length!=0)
{
BeginIO((struct IORequest *)iob2_left);
BeginIO((struct IORequest *)iob2_right);
}
/* If the sound sample was small enough to fit into the two buffers, */
/* play them then finish up */
if(length==0)
{
Wait((1<<iob1_left->ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) |
(1<<window->UserPort->mp_SigBit));
if(iob2_left->ioa_Length!=0 && GetMsg(window->UserPort)==NULL)
Wait((1<<iob2_left->ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) |
(1<<window->UserPort->mp_SigBit));
done=TRUE;
}
/*Otherwise, play those samples then read more from disk*/
/*Loop while there's stuff to read*/
while(!done)
{
/*Wait for the first buffer to finish playing*/
Wait((1<<iob1_left->ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) |
(1<<window->UserPort->mp_SigBit));
toRead=MIN(length,bufSize);
if(GetMsg(window->UserPort)!=NULL)
{
done=TRUE;
break;
}
else
if(toRead==0)
{
/*If there's no stuff left to read, wait 'till the second buffer*/
/*finishes, then quit*/
Wait((1<<iob1_left->ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) |
(1<<window->UserPort->mp_SigBit));
done=TRUE;
break;
}
LoadAudioBuffer(leftFile,iob1_left,toRead);
LoadAudioBuffer(rightFile,iob1_right,toRead);
length-=toRead;
if(length==0 && loop)
{
length=sampleSize;
Seek(leftFile,-sampleSize,OFFSET_CURRENT);
Seek(rightFile,-sampleSize,OFFSET_CURRENT);
}
iob1_left->ioa_Length=iob1_right->ioa_Length=toRead;
/*Play the first buffer*/
BeginIO((struct IORequest *)iob1_left);
BeginIO((struct IORequest *)iob1_right);
/*Wait for the second buffer to finish*/
Wait((1<<iob2_left->ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) |
(1<<window->UserPort->mp_SigBit));
toRead=MIN(length,bufSize);
if(GetMsg(window->UserPort)!=NULL)
{
done=TRUE;
break;
}
else
if(toRead==0)
{
/*If there's no stuff left to read, wait 'till the first buffer*/
/*finishes, then quit*/
Wait((1<<iob1_left->ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) |
(1<<window->UserPort->mp_SigBit));
done=TRUE;
break;
}
/*Reload it*/
LoadAudioBuffer(leftFile,iob2_left,toRead);
LoadAudioBuffer(rightFile,iob2_right,toRead);
length-=toRead;
if(length==0 && loop)
{
length=sampleSize;
Seek(leftFile,-sampleSize,OFFSET_CURRENT);
Seek(rightFile,-sampleSize,OFFSET_CURRENT);
}
iob2_left->ioa_Length=iob2_right->ioa_Length=toRead;
/*Play it*/
BeginIO((struct IORequest *)iob2_left);
BeginIO((struct IORequest *)iob2_right);
}
/*Restore the buffer lengths, so that FreeAudio() channel, etc., knows*/
/*how much memory to free*/
iob1_left->ioa_Length=iob2_left->ioa_Length=bufSize;
iob1_right->ioa_Length=iob2_right->ioa_Length=bufSize;
FreeAudioChannel(iob1_left);
DeleteDuplication(iob2_left);
FreeAudioChannel(iob1_right);
DeleteDuplication(iob2_right);
if(rightFile != 4L)
Close(rightFile);
return;
}
/*Play a mono sample (or a single channel of a stereo sample) out of */
/*both speakers simultaneously*/
void playMonoTwice(BPTR file,channel audioChannel,struct Voice8Header *vhdr,
ULONG length)
{
struct IOAudio *iob1_right,*iob2_right,*iob1_left,*iob2_left;
ULONG toRead;
ULONG sampleSize=length;
BOOL done=FALSE;
/*Read the entire sample into memory, if the user so specified*/
if(readAll)
{
storeLeft(file,length,bufSize);
file=0L;
}
/*Get the first audio channel*/
iob1_left=GetAudioChannel(bufSize,leftAMap);
if(iob1_left==NULL)
{
WriteMsg("Couldn't create the first stereo buffer\n");
cleanup(150);
}
iob1_right=GetAudioChannel(bufSize,rightAMap);
if(iob1_right==NULL)
{
WriteMsg("Couldn't create the second stereo buffer\n");
cleanup(150);
}
FreeMem(iob1_right->ioa_Data,iob1_right->ioa_Length);
iob1_right->ioa_Data=iob1_left->ioa_Data;
/* If the user didn't specify a volume, get it from the VHDR */
if(volume==0)
volume=(vhdr->volume>>10);
/* If the VHDR gave a volume of zero, use maximum volume*/
if(volume==0)
volume=64;
/* Get the samples/sec rate (either the rate given by the user, or the*/
/* rate found in the VHDR) */
if(speed==0)
speed=1000000000/(vhdr->samplesPerSec*279);
else
speed=1000000000/(speed*279);
InitAudioChannel(iob1_left,volume,speed);
InitAudioChannel(iob1_right,volume,speed);
/*Get the 2nd audio channel*/
iob2_left=DuplicateAudioChannel(iob1_left);
if(iob2_left==NULL)
{
FreeAudioChannel(iob1_left);
FreeAudioChannel(iob1_right);
WriteMsg("Couldn't create the second buffer");
cleanup(175);
}
iob2_right=DuplicateAudioChannel(iob1_right);
if(iob2_right==NULL)
{
FreeAudioChannel(iob1_left);
DeleteDuplication(iob2_left);
FreeAudioChannel(iob1_right);
WriteMsg("Couldn't create the second buffer");
cleanup(175);
}
FreeMem(iob2_right->ioa_Data,iob2_right->ioa_Length);
iob2_right->ioa_Data=iob2_left->ioa_Data;
/* Load the first buffer*/
toRead=MIN(length,bufSize);
LoadAudioBuffer(file,iob1_left,toRead);
length-=toRead;
if(length==0 && loop)
{
length=sampleSize;
Seek(file,-sampleSize,OFFSET_CURRENT);
}
iob1_right->ioa_Length=iob1_left->ioa_Length=toRead;
/* Make sure there's enough data so that we have something to put in */
/* the second buffer */
if(length!=0)
{
toRead=MIN(length,bufSize);
LoadAudioBuffer(file,iob2_left,toRead);
length-=toRead;
if(length==0 && loop)
{
length=sampleSize;
Seek(file,-sampleSize,OFFSET_CURRENT);
}
iob2_right->ioa_Length=iob2_left->ioa_Length=toRead;
}
else
/* It appears that the entire sound sample is small enough to */
/* fit into the first buffer, so don't play the second */
iob2_left->ioa_Length=iob2_right->ioa_Length=0;
/*And queue up the play requests*/
BeginIO((struct IORequest *)iob1_left);
BeginIO((struct IORequest *)iob1_right);
if(iob2_left->ioa_Length!=0)
{
BeginIO((struct IORequest *)iob2_left);
BeginIO((struct IORequest *)iob2_right);
}
/* If the sound sample was small enough to fit into the two buffers, */
/* play them then finish up */
if(GetMsg(window->UserPort)!=NULL)
done=TRUE;
else
if(length==0)
{
/* Bug!!! */
Wait((1<<iob1_left->ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) |
(1<<window->UserPort->mp_SigBit));
if(iob2_left->ioa_Length!=0 && GetMsg(window->UserPort)==NULL)
Wait((1<<iob2_left->ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) |
(1<<window->UserPort->mp_SigBit));
done=TRUE;
}
/*Otherwise, play those samples then read more from disk*/
/*Loop while there's stuff to read*/
while(!done)
{
/*Fill the first buffer*/
Wait((1<<iob1_left->ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) |
(1<<window->UserPort->mp_SigBit));
toRead=MIN(length,bufSize);
if(GetMsg(window->UserPort)!=NULL)
{
done=TRUE;
break;
}
else
if(toRead==0)
{
/*If there's no stuff left to read, wait 'till the second buffer*/
/*finishes, then quit*/
Wait((1<<iob2_left->ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) |
(1<<window->UserPort->mp_SigBit));
done=TRUE;
break;
}
LoadAudioBuffer(file,iob1_left,toRead);
length-=toRead;
if(length==0 && loop)
{
length=sampleSize;
Seek(file,-sampleSize,OFFSET_CURRENT);
}
iob1_right->ioa_Length=iob1_left->ioa_Length=toRead;
/*Play the first buffer*/
BeginIO((struct IORequest *)iob1_left);
BeginIO((struct IORequest *)iob1_right);
/*Wait for the second buffer to finish*/
Wait((1<<iob2_left->ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) |
(1<<window->UserPort->mp_SigBit));
toRead=MIN(length,bufSize);
if(GetMsg(window->UserPort)!=NULL)
{
done=TRUE;
break;
}
else
if(toRead==0)
{
/*If there's no stuff left to read, wait 'till the first buffer*/
/*finishes, then quit*/
Wait((1<<iob1_left->ioa_Request.io_Message.mn_ReplyPort->mp_SigBit) |
(1<<window->UserPort->mp_SigBit));
done=TRUE;
break;
}
/*Reload it*/
LoadAudioBuffer(file,iob2_left,toRead);
length-=toRead;
if(length==0 && loop)
{
length=sampleSize;
Seek(file,-sampleSize,OFFSET_CURRENT);
}
iob2_right->ioa_Length=iob2_left->ioa_Length=toRead;
/*Play it*/
BeginIO((struct IORequest *)iob2_left);
BeginIO((struct IORequest *)iob2_right);
}
/*Restore the buffer lengths, so that FreeAudio() channel, etc., knows*/
/*how much memory to free*/
iob1_left->ioa_Length=iob2_left->ioa_Length=bufSize;
iob1_right->ioa_Length=iob2_right->ioa_Length=bufSize;
iob1_right->ioa_Data=NULL;
iob2_right->ioa_Data=NULL;
FreeAudioChannel(iob1_left);
DeleteDuplication(iob2_left);
FreeAudioChannel(iob1_right);
DeleteDuplication(iob2_right);
return;
}
/*End of Play.c*/